package com.yiba.vpn.utils;

import com.yiba.logutils.LogUtils;
import com.yiba.vpn.VPNServiceManager;
import com.yiba.vpn.core.LocalVpnService;
import com.yiba.vpn.utils.logger.LogUtil;

import java.util.Locale;

/**
 * http post header解析
 */
public class HttpHostHeaderParser {

    public static String parseHost(byte[] buffer, int offset, int count) {
        try {
            switch (buffer[offset]) {
                case 'G'://GET
                case 'H'://HEAD
                case 'P'://POST,PUT
                case 'D'://DELETE
                case 'O'://OPTIONS
                case 'T'://TRACE
                case 'C'://CONNECT
                    return getHttpHost(buffer, offset, count);
                case 0x16://SSL
                    return getSNI(buffer, offset, count);
            }
        } catch (Exception e) {
            e.printStackTrace();
            LocalVpnService.Instance.writeLog("Error: parseHost:%s", e);
        }
        return null;
    }

    static String getHttpHost(byte[] buffer, int offset, int count) {
        String headerString = new String(buffer, offset, count);
        String[] headerLines = headerString.split("\\r\\n");
        String host = getHttpHost(headerLines);
        paresRequestLine(headerLines[0],host);
        return null;
    }

    /**
     * 进一步的解析http的request url
     * @param headerLines
     * @return
     */
    public static String getHttpHost(String[] headerLines) {
        String requestLine = headerLines[0];
        if (requestLine.startsWith("GET") || requestLine.startsWith("POST") || requestLine.startsWith("HEAD")
                || requestLine.startsWith("OPTIONS")) {
            for (int i = 1; i < headerLines.length; i++) {
                String[] nameValueStrings = headerLines[i].split(":");
                if (nameValueStrings.length == 2) {
                    String name = nameValueStrings[0].toLowerCase(Locale.ENGLISH).trim();
                    String value = nameValueStrings[1].trim();
                    if ("host".equals(name)) {
                        return value;
                    }
                }
            }
        }
        return null;
    }


    /**
     * 解析HTTP 的url、method
     * @param requestLine
     * @param host
     */
    private static void paresRequestLine(String requestLine,String host) {
        String[] parts = requestLine.trim().split(" ");
        if (parts.length == 3) {
            if(LogUtil.OPEN_LOG){
                LogUtil.i("http请求的method==>"+parts[0]);
            }
            LogUtils.getInstance().log(VPNServiceManager.TAG,"http请求的method==>"+parts[0]);
            String url = parts[1];
            if (url.startsWith("/")) {
                if(LogUtil.OPEN_LOG){
                    LogUtil.i("http请求的url==>"+host+url);
                }
                LogUtils.getInstance().log(VPNServiceManager.TAG,"http请求的url==>"+host+url);
            } else {
                if(LogUtil.OPEN_LOG){
                    LogUtil.i("http请求的url==>"+url);
                }LogUtils.getInstance().log(VPNServiceManager.TAG,"http请求的url==>"+url);
            }
        }
    }

    static String getSNI(byte[] buffer, int offset, int count) {
        int limit = offset + count;
        if (count > 43 && buffer[offset] == 0x16) {//TLS Client Hello
            offset += 43;//skip 43 bytes header

            //read sessionID:
            if (offset + 1 > limit) return null;
            int sessionIDLength = buffer[offset++] & 0xFF;
            offset += sessionIDLength;

            //read cipher suites:
            if (offset + 2 > limit) return null;
            int cipherSuitesLength = CommonMethods.readShort(buffer, offset) & 0xFFFF;
            offset += 2;
            offset += cipherSuitesLength;

            //read Compression method:
            if (offset + 1 > limit) return null;
            int compressionMethodLength = buffer[offset++] & 0xFF;
            offset += compressionMethodLength;

            if (offset == limit) {
                System.err.println("TLS Client Hello packet doesn't contains SNI info.(offset == limit)");
                return null;
            }

            //read Extensions:
            if (offset + 2 > limit) return null;
            int extensionsLength = CommonMethods.readShort(buffer, offset) & 0xFFFF;
            offset += 2;

            if (offset + extensionsLength > limit) {
                System.err.println("TLS Client Hello packet is incomplete.");
                return null;
            }

            while (offset + 4 <= limit) {
                int type0 = buffer[offset++] & 0xFF;
                int type1 = buffer[offset++] & 0xFF;
                int length = CommonMethods.readShort(buffer, offset) & 0xFFFF;
                offset += 2;

                if (type0 == 0x00 && type1 == 0x00 && length > 5) { //have SNI
                    offset += 5;//skip SNI header.
                    length -= 5;//SNI size;
                    if (offset + length > limit) return null;
                    String serverName = new String(buffer, offset, length);
                    if (LogUtil.OPEN_LOG)
                        System.out.printf("SNI: %s\n", serverName);
                    return serverName;
                } else {
                    offset += length;
                }
            }

            System.err.println("TLS Client Hello packet doesn't contains Host field info.");
            return null;
        } else {
            System.err.println("Bad TLS Client Hello packet.");
            return null;
        }
    }
}
